package com.zrkizzy.linkedlist;

/**
 * 19. 删除链表的倒数第 N 个结点<br/>
 * https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/
 *
 * @author zhangrongkang
 * @date 2022/11/17
 */
public class 删除链表的倒数第N个结点 {
    class ListNode {
        int val;
        ListNode next;

        ListNode() {}

        ListNode(int val) {
            this.val = val;
        }

        ListNode(int val, ListNode next) {
            this.val = val;
            this.next = next;
        }
    }

    class Solution01 {
        // 双指针 + 一次扫描
        public ListNode removeNthFromEnd(ListNode head, int n) {
            // 定义快慢指针
            ListNode slow = head, fast = head;

            // 快指针先走n步
            for (int i = 0; i < n; i++) {
                fast = fast.next;
            }

            // 如果此时快指针的位置为null，说明要删除的是头节点
            if (fast == null) {
                return head.next;
            }

            // 同时移动快慢指针，直到快指针为null
            while (fast.next != null) {
                fast = fast.next;
                slow = slow.next;
            }
            // 此时slow为要删除的节点的前一个
            slow.next = slow.next.next;
            return head;
        }
    }

    class Solution02 {

        // 迭代 + 两次扫描
        public ListNode removeNthFromEnd(ListNode head, int n) {
            // 定义虚拟节点
            ListNode node = new ListNode(0, head), result = node;
            int size = getSize(head);
            // 定义要遍历到的索引
            int index = size - n;
            for (int i = 0; i < index; i++) {
                node = node.next;
            }
            // 此时node的位置是要删除节点的前一个
            node.next = node.next.next;
            return result.next;
        }

        // 获取链表长度
        private int getSize(ListNode node) {
            ListNode temp = node;
            int size = 1;
            // 获取链表的长度
            while (temp.next != null) {
                size++;
                temp = temp.next;
            }
            return size;
        }
    }


}
